(* list all used variables *)

use "ast.sml";

infix :+:;
infix \\;

local val rec op \\ : id list * id -> id list =
       fn ([], x') => [x']
	| (x::xs, x') => if (x=x') then xs
			   else x :: (xs \\ x)
in val rec op :+: : id list * id list -> id list =
    fn ([], is') => is'
     | (i::is, is') => i :: (is :+: (is' \\ i))
end;

local val rec listVarsExp : exp -> id list =
       fn IdExp i => [i]
	| NumExp _ => []
	| OpExp (l, _, r) => (listVarsExp l) :+: (listVarsExp r)
	| EseqExp (s, e) => (listVarsStm s) :+: (listVarsExp e)
    and listVarsExps : exp list -> id list =
     fn [] => []
      | (e :: es) => (listVarsExp e) :+: (listVarsExps es)
    and listVarsStm : stm -> id list =
     fn CompoundStm (s, s') => (listVarsStm s) :+: (listVarsStm s')
      | AssignStm (i, e) => i :: (listVarsExp e)
      | PrintStm es => listVarsExps es
in val listVars : prg -> id list = listVarsStm
end;

use "progs.sml";

local val rec member : id * id list -> bool =
       fn (i', []) => false
	| (i', i::is) => i=i' orelse member (i', is)
    and members : id list * id list -> bool =
     fn ([], is) => true
      | (i::is, is') => member (i, is') andalso members (is, is')
in val rec same : id list * id list -> bool =
    fn (is, is') => members (is, is') andalso members (is', is)
end;

use "assert.sml";

assert (same (listVars prog1,  ["i"]),      "P1");
assert (same (listVars prog2,  ["i", "j"]), "P2");
assert (same (listVars prog3,  ["j"]),      "P3");
assert (same (listVars prog4,  ["i", "j"]), "P4");
assert (same (listVars prog5,  ["i", "j"]), "P5");
assert (same (listVars prog6,  ["i", "j"]), "P6");
assert (same (listVars prog7,  []),         "P7");
assert (same (listVars prog8,  []),         "P8");
assert (same (listVars prog9,  []),         "P9");
assert (same (listVars prog10, []),         "P10");
assert (same (listVars prog11, ["i", "j"]), "P11");
assert (same (listVars prog12, ["i", "j"]), "P12");
assert (same (listVars prog13, ["i", "j"]), "P13");
assert (same (listVars prog14, ["i", "j"]), "P14");
assert (same (listVars prog15, ["a", "b"]), "P15");
assert (same (listVars prog16, ["a", "b"]), "P16");

OS.Process.exit OS.Process.success;
